home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / msdos / raytrace / pov / source / lighting.c < prev    next >
C/C++ Source or Header  |  1994-01-05  |  39KB  |  1,258 lines

  1. /****************************************************************************
  2. *                   lighting.c
  3. *
  4. *  This module calculates lighting properties like ambient, diffuse, specular,
  5. *  reflection, refraction, etc.
  6. *
  7. *  from Persistence of Vision Raytracer
  8. *  Copyright 1993 Persistence of Vision Team
  9. *---------------------------------------------------------------------------
  10. *  NOTICE: This source code file is provided so that users may experiment
  11. *  with enhancements to POV-Ray and to port the software to platforms other
  12. *  than those supported by the POV-Ray Team.  There are strict rules under
  13. *  which you are permitted to use this file.  The rules are in the file
  14. *  named POVLEGAL.DOC which should be distributed with this file. If
  15. *  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  16. *  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  17. *  Forum.  The latest version of POV-Ray may be found there as well.
  18. *
  19. * This program is based on the popular DKB raytracer version 2.12.
  20. * DKBTrace was originally written by David K. Buck.
  21. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  22. *
  23. *****************************************************************************/
  24.  
  25. #include "frame.h"
  26. #include "vector.h"
  27. #include "povproto.h"
  28.  
  29. extern int Trace_Level;
  30. extern FRAME Frame;
  31. extern OBJECT *Root_Object;
  32. extern unsigned int Options;
  33. extern int Use_Slabs;
  34. extern unsigned long Quality_Flags;
  35. extern int Shadow_Test_Flag;
  36. extern long Shadow_Ray_Tests, Shadow_Rays_Succeeded, Shadow_Cache_Hits;
  37. extern long Reflected_Rays_Traced, Refracted_Rays_Traced;
  38. extern long Transmitted_Rays_Traced;
  39.  
  40. extern short *hashTable;
  41. extern unsigned short crctab[256];
  42. #define rand3d(a,b) crctab[(int)(hashTable[(int)(hashTable[(int)((a)&0xfff)]^(b))&0xfff])&0xff]
  43.  
  44. #define COORDINATE_LIMIT 1.0e17
  45. #define BLACK_LEVEL 0.003
  46.  
  47. /* "Small_Tolerance" is just too tight for higher order polynomial equations.
  48.    this value should probably be a variable of some sort, but for now just
  49.    use a reasonably small value.  If people render real small objects real
  50.    close to each other then there may be some shading problems.  Otherwise
  51.    having SHADOW_TOLERANCE as large as this won't affect images. */
  52. #define SHADOW_TOLERANCE 1.0e-3
  53.  
  54. static void do_light PARAMS((LIGHT_SOURCE *Light_Source,
  55. DBL *Light_Source_Depth, RAY *Light_Source_Ray, VECTOR *IPoint,
  56. COLOUR *Light_Colour));
  57. static int do_blocking PARAMS((INTERSECTION *Local_Intersection,
  58. COLOUR *Light_Colour, ISTACK *Local_Stack));
  59. static void do_phong PARAMS((FINISH *Finish, RAY *Light_Source_Ray,
  60. VECTOR *Eye, VECTOR *Layer_Normal, COLOUR *Colour, COLOUR *Light_Colour,
  61. COLOUR *Layer_Pigment_Colour));
  62. static void do_specular PARAMS((FINISH *Finish, RAY *Light_Source_Ray,
  63. VECTOR *REye, VECTOR *Layer_Normal, COLOUR *Colour, COLOUR *Light_Colour,
  64. COLOUR *Layer_Pigment_Colour));
  65. static void do_diffuse PARAMS((FINISH *Finish, RAY *Light_Source_Ray,
  66. VECTOR *Layer_Normal, COLOUR *Colour, COLOUR *Light_Colour,
  67. COLOUR *Layer_Pigment_Colour, DBL Attenuation));
  68. static void Block_Area_Light PARAMS((LIGHT_SOURCE *Light_Source,
  69. DBL Light_Source_Depth, RAY *Light_Source_Ray_Ptr, VECTOR *IPoint,
  70. COLOUR *Light_Colour, int u1, int v1, int u2, int v2, int Level));
  71. static void Block_Point_Light PARAMS((LIGHT_SOURCE *Light_Source,
  72. DBL Light_Source_Depth, RAY *Light_Source_Ray_Ptr, COLOUR *Light_Colour));
  73.  
  74. static void Block_Point_Light (Light_Source, Light_Source_Depth, Light_Source_Ray_Ptr, Light_Colour)
  75. LIGHT_SOURCE *Light_Source;
  76. DBL Light_Source_Depth;
  77. RAY *Light_Source_Ray_Ptr;
  78. COLOUR *Light_Colour;
  79.   {
  80.   OBJECT *Blocking_Object;
  81.   int Quit_Looking, Not_Found_Shadow, Cache_Me;
  82.   INTERSECTION *Local_Intersection, Bounded_Intersection;
  83.   ISTACK *Local_Stack;
  84.   RAY Local_Ray;
  85.   RAY Light_Source_Ray;
  86.  
  87.   Light_Source_Ray = *Light_Source_Ray_Ptr;
  88.  
  89.   Local_Stack = open_istack ();
  90.   Quit_Looking = FALSE;
  91.  
  92.   /* Test the cached object first */
  93.   /* Made changes so that semi-transparent objects never get cached */
  94.   if (Light_Source->Shadow_Cached_Object != NULL) 
  95.     {
  96.     Shadow_Ray_Tests++;
  97.  
  98.     if (Ray_In_Bounds (&Light_Source_Ray, Light_Source->Shadow_Cached_Object->Bound))
  99.       {
  100.       if (All_Intersections (Light_Source->Shadow_Cached_Object, &Light_Source_Ray, Local_Stack))
  101.         while ((Local_Intersection=pop_entry(Local_Stack)) != NULL)
  102.           {
  103.           if ((!Local_Intersection->Object->No_Shadow_Flag) && 
  104.             (Local_Intersection->Depth < Light_Source_Depth-Small_Tolerance) && 
  105.             (Local_Intersection->Depth > SHADOW_TOLERANCE))
  106.             if (do_blocking(Local_Intersection, Light_Colour, Local_Stack))
  107.               {
  108.               Quit_Looking = TRUE;
  109.               Shadow_Cache_Hits++;
  110.               break;
  111.               }
  112.           }
  113.       }
  114.     }
  115.  
  116.   if (Quit_Looking) 
  117.     {
  118.     close_istack (Local_Stack);
  119.     return;
  120.     }
  121.  
  122.   Not_Found_Shadow = TRUE;   
  123.   Cache_Me = FALSE;
  124.   if (!Use_Slabs)
  125.     {
  126.     for (Blocking_Object = Frame.Objects;
  127.     Blocking_Object != NULL;
  128.     Blocking_Object = Blocking_Object->Sibling)
  129.       {
  130.       if (Blocking_Object == Light_Source->Shadow_Cached_Object)
  131.         continue;
  132.  
  133.       Shadow_Ray_Tests++;
  134.  
  135.       if (!Ray_In_Bounds (&Light_Source_Ray, Blocking_Object->Bound))
  136.         continue;
  137.  
  138.       if (!All_Intersections (Blocking_Object, &Light_Source_Ray, Local_Stack))
  139.         continue;
  140.  
  141.       while ((Local_Intersection = pop_entry(Local_Stack)) != NULL)
  142.         if ((!Local_Intersection->Object->No_Shadow_Flag) && 
  143.           (Local_Intersection->Depth < Light_Source_Depth-Small_Tolerance) && 
  144.           (Local_Intersection->Depth > SHADOW_TOLERANCE))
  145.           {
  146.           if (do_blocking(Local_Intersection, Light_Colour, Local_Stack))
  147.             {
  148.             Cache_Me = Not_Found_Shadow;
  149.             Quit_Looking = TRUE;
  150.             break; /* from while */
  151.             }
  152.           Not_Found_Shadow = FALSE;
  153.           }
  154.       if (Quit_Looking)
  155.         break; /* from for */
  156.       }
  157.     }
  158.   else   /* Use bounding slabs to look for shadows */
  159.     {
  160.     Local_Ray = Light_Source_Ray;
  161.     while (!Quit_Looking) 
  162.       {
  163.       Shadow_Ray_Tests++;
  164.       Local_Ray.Quadric_Constants_Cached = 0;
  165.       Bounded_Intersection.Depth = Light_Source_Depth;
  166.       if (Bounds_Intersect(Root_Object, &Local_Ray, &Bounded_Intersection,
  167.         &Blocking_Object)) 
  168.         {
  169.         if (Bounded_Intersection.Depth > Light_Source_Depth) 
  170.           break; /* Intersection was beyond the light */
  171.  
  172.         if (!(Bounded_Intersection.Object->No_Shadow_Flag))
  173.           if (Blocking_Object != Light_Source->Shadow_Cached_Object)
  174.             {
  175.             Shadow_Rays_Succeeded++;
  176.             Filter_Shadow_Ray(&Bounded_Intersection, Light_Colour);
  177.             if ((fabs(Light_Colour->Red) < BLACK_LEVEL) &&
  178.               (fabs(Light_Colour->Green) < BLACK_LEVEL) &&
  179.               (fabs(Light_Colour->Blue) < BLACK_LEVEL))
  180.               {
  181.               Cache_Me = Not_Found_Shadow;
  182.               Quit_Looking = TRUE;
  183.               break; /* from while */
  184.               }
  185.             }
  186.         /* Move the ray to the point of intersection, plus some */
  187.         Light_Source_Depth -= Bounded_Intersection.Depth;
  188.         Local_Ray.Initial = Bounded_Intersection.IPoint;
  189.         Not_Found_Shadow = FALSE;
  190.         }
  191.       else /* No intersections in the direction of the ray */
  192.         {
  193.         break;
  194.         }
  195.       } /*endwhile*/
  196.     } /*endelse*/
  197.   if (Cache_Me) 
  198.     Light_Source->Shadow_Cached_Object = Blocking_Object;
  199.   close_istack (Local_Stack);
  200.   }
  201.  
  202.  
  203. static void Block_Area_Light (Light_Source, Light_Source_Depth,
  204. Light_Source_Ray_Ptr,IPoint, Light_Colour, u1, v1, u2, v2, Level)
  205. LIGHT_SOURCE *Light_Source;
  206. DBL Light_Source_Depth;
  207. RAY *Light_Source_Ray_Ptr;
  208. VECTOR *IPoint;
  209. COLOUR *Light_Colour;
  210. int u1, v1, u2, v2, Level;
  211.   {
  212.   COLOUR Sample_Colour[4], Dummy_Colour;
  213.   VECTOR Center_Save, NewAxis1, NewAxis2;
  214.   int i, j, u, v, New_u1, New_v1, New_u2, New_v2;
  215.  
  216.   DBL Jitter_u, Jitter_v, ScaleFactor;
  217.   RAY Light_Source_Ray;
  218.  
  219.   Light_Source_Ray = *Light_Source_Ray_Ptr;
  220.  
  221.   /* First call, initialize */
  222.   if (u1 == 0 && v1 == 0 && u2 == 0 && v2 == 0) 
  223.     {
  224.     /* Flag uncalculated points with a negative value for Red */
  225.     for (i = 0; i < Light_Source->Area_Size1; i++) 
  226.       {
  227.       for (j = 0; j < Light_Source->Area_Size2; j++)
  228.         Light_Source->Light_Grid[i][j].Red = -1.0;
  229.       }
  230.  
  231.     u1 = 0;
  232.     v1 = 0;
  233.     u2 = Light_Source->Area_Size1 - 1;
  234.     v2 = Light_Source->Area_Size2 - 1;
  235.     }
  236.  
  237.   /* Save the light source center since we'll be fiddling with it */
  238.   Center_Save=Light_Source->Center;
  239.  
  240.   /* Sample the four corners of the region */
  241.   for (i = 0; i < 4; i++) 
  242.     {
  243.     switch (i) 
  244.     {
  245.     case 0: 
  246.       u = u1; v = v1; break;
  247.     case 1: 
  248.       u = u2; v = v1; break;
  249.     case 2: 
  250.       u = u1; v = v2; break;
  251.     case 3: 
  252.       u = u2; v = v2; break;
  253.     }
  254.  
  255.     if (Light_Source -> Light_Grid[u][v].Red >= 0.0)
  256.       /* We've already calculated this point, reuse it */
  257.       Sample_Colour[i]=Light_Source->Light_Grid[u][v];
  258.     else 
  259.       {
  260.       Jitter_u = (DBL)u;
  261.       Jitter_v = (DBL)v;
  262.  
  263.       if (Light_Source -> Jitter) 
  264.         {
  265.         Jitter_u += (rand() % 4096)/4096.0 - 0.5;
  266.         Jitter_v += (rand() % 4096)/4096.0 - 0.5;
  267.         /*
  268.   Not sure if    jx = IPoint->x + 100*u;
  269.   this works    jy = IPoint->y + 100*v;
  270.   yet
  271.         Jitter_u += ((rand3d(jx, jy) & 0x7FFF)/32768.0) - 0.5;
  272.         Jitter_v += ((rand3d(jx+10, jy+10) & 0x7FFF)/32768.0) - 0.5;
  273. */
  274.         }
  275.  
  276.       if (Light_Source -> Area_Size1 > 1) 
  277.         {
  278.         ScaleFactor = Jitter_u/(DBL)(Light_Source->Area_Size1 - 1) - 0.5;
  279.         VScale (NewAxis1, Light_Source->Axis1, ScaleFactor)
  280.           }
  281.       else
  282.         Make_Vector (&NewAxis1, 0.0, 0.0, 0.0);
  283.  
  284.       if (Light_Source -> Area_Size2 > 1) 
  285.         {
  286.         ScaleFactor = Jitter_v/(DBL)(Light_Source->Area_Size2 - 1) - 0.5;
  287.         VScale (NewAxis2, Light_Source->Axis2, ScaleFactor)
  288.         }
  289.       else
  290.         Make_Vector (&NewAxis2, 0.0, 0.0, 0.0);
  291.  
  292.       Light_Source->Center=Center_Save;
  293.       VAdd  (Light_Source->Center, Light_Source->Center, NewAxis1);
  294.       VAdd  (Light_Source->Center, Light_Source->Center, NewAxis2);
  295.  
  296.       /* Recalculate the light source ray but not the colour */
  297.       do_light (Light_Source, &Light_Source_Depth, &Light_Source_Ray,
  298.         IPoint, &Dummy_Colour);
  299.  
  300.       Sample_Colour[i]= *Light_Colour;
  301.  
  302.       Block_Point_Light (Light_Source, Light_Source_Depth,
  303.         &Light_Source_Ray, &Sample_Colour[i]);
  304.  
  305.       Light_Source->Light_Grid[u][v]=Sample_Colour[i];
  306.       }
  307.     }
  308.  
  309.   Light_Source->Center=Center_Save;
  310.  
  311.   if ( (u2 - u1 > 1 || v2 - v1 > 1) && (Level < Light_Source -> Adaptive_Level ||
  312.     Colour_Distance (&Sample_Colour[0], &Sample_Colour[1]) > 0.1 ||
  313.     Colour_Distance (&Sample_Colour[1], &Sample_Colour[3]) > 0.1 ||
  314.     Colour_Distance (&Sample_Colour[3], &Sample_Colour[2]) > 0.1 ||
  315.     Colour_Distance (&Sample_Colour[2], &Sample_Colour[0]) > 0.1) )
  316.     {
  317.     for (i = 0; i < 4; i++) 
  318.       {
  319.       switch (i) 
  320.       {
  321.       case 0: 
  322.         New_u1 = u1;
  323.         New_v1 = v1;
  324.         New_u2 = (int)floor ((u1 + u2)/2.0);
  325.         New_v2 = (int)floor ((v1 + v2)/2.0);
  326.         break;
  327.  
  328.       case 1: 
  329.         New_u1 = (int)ceil  ((u1 + u2)/2.0);
  330.         New_v1 = v1;
  331.         New_u2 = u2;
  332.         New_v2 = (int)floor ((v1 + v2)/2.0);
  333.         break;
  334.  
  335.       case 2: 
  336.         New_u1 = u1;
  337.         New_v1 = (int)ceil  ((v1 + v2)/2.0);
  338.         New_u2 = (int)floor ((u1 + u2)/2.0);
  339.         New_v2 = v2;
  340.         break;
  341.  
  342.       case 3: 
  343.         New_u1 = (int)ceil ((u1 + u2)/2.0);
  344.         New_v1 = (int)ceil ((v1 + v2)/2.0);
  345.         New_u2 = u2;
  346.         New_v2 = v2;
  347.         break;
  348.       }
  349.  
  350.       /* Recalculate the light source ray but not the colour */
  351.       do_light (Light_Source, &Light_Source_Depth, &Light_Source_Ray,
  352.         IPoint, &Dummy_Colour);
  353.  
  354.       Sample_Colour[i]= *Light_Colour;
  355.  
  356.       Block_Area_Light (Light_Source, Light_Source_Depth,
  357.         &Light_Source_Ray, IPoint,
  358.         &Sample_Colour[i],
  359.         New_u1, New_v1, New_u2, New_v2, Level+1);
  360.       }
  361.     }
  362.  
  363.   /* Add up the light contributions */
  364.   Make_Colour (Light_Colour, 0.0, 0.0, 0.0);
  365.  
  366.   for (i = 0; i < 4; i++) 
  367.     {
  368.     Scale_Colour (&Sample_Colour[i], &Sample_Colour[i], 0.25);
  369.     Add_Colour (Light_Colour, Light_Colour, &Sample_Colour[i]);
  370.     }
  371.   }
  372.  
  373. static void do_light(Light_Source, Light_Source_Depth, Light_Source_Ray, IPoint, Light_Colour)
  374. LIGHT_SOURCE *Light_Source;
  375. DBL *Light_Source_Depth;
  376. RAY *Light_Source_Ray;
  377. VECTOR *IPoint;
  378. COLOUR *Light_Colour;
  379.   {
  380.   DBL Attenuation = 1.0;
  381.  
  382.   /* Get the light source colour. */
  383.   *Light_Colour = Light_Source->Colour;
  384.  
  385.   Light_Source_Ray->Initial = *IPoint;
  386.   Light_Source_Ray->Quadric_Constants_Cached = FALSE;
  387.  
  388.   VSub (Light_Source_Ray->Direction,
  389.     Light_Source->Center,
  390.     *IPoint);
  391.  
  392.   VLength (*Light_Source_Depth, Light_Source_Ray->Direction);
  393.  
  394.   VScale (Light_Source_Ray->Direction, Light_Source_Ray->Direction,
  395.     1.0/(*Light_Source_Depth));
  396.  
  397.   Attenuation = Attenuate_Light(Light_Source, Light_Source_Ray);
  398.  
  399.   /* Now scale the color by the attenuation */
  400.   Light_Colour->Red   *= Attenuation;
  401.   Light_Colour->Green *= Attenuation;
  402.   Light_Colour->Blue  *= Attenuation;
  403.  
  404.  
  405.   return;
  406.   }
  407.  
  408. static int do_blocking(Local_Intersection, Light_Colour, Local_Stack)
  409. INTERSECTION *Local_Intersection;
  410. COLOUR *Light_Colour;
  411. ISTACK *Local_Stack;
  412.   {
  413.   Shadow_Rays_Succeeded++;
  414.  
  415.   Filter_Shadow_Ray (Local_Intersection, Light_Colour);
  416.  
  417.   if ((fabs(Light_Colour->Red) < BLACK_LEVEL) && 
  418.     (fabs(Light_Colour->Green) < BLACK_LEVEL) && 
  419.     (fabs(Light_Colour->Blue) < BLACK_LEVEL)) 
  420.     {
  421.     while ((Local_Intersection = pop_entry(Local_Stack)) != NULL)
  422.       {
  423.       }
  424.     return(TRUE);
  425.     }
  426.   return(FALSE);
  427.   }
  428.  
  429. static void do_phong(Finish, Light_Source_Ray, Eye, Layer_Normal, Colour, Light_Colour, Layer_Pigment_Colour)
  430. FINISH *Finish;
  431. RAY *Light_Source_Ray;
  432. VECTOR *Layer_Normal, *Eye;
  433. COLOUR *Colour, *Light_Colour, *Layer_Pigment_Colour;
  434.   {
  435.   DBL Cos_Angle_Of_Incidence, Normal_Length, Intensity;
  436.   VECTOR Local_Normal, Normal_Projection, Reflect_Direction;
  437.  
  438.   VDot(Cos_Angle_Of_Incidence, *Eye, *Layer_Normal);
  439.  
  440.   if (Cos_Angle_Of_Incidence < 0.0)
  441.     {
  442.     Local_Normal = *Layer_Normal;
  443.     Cos_Angle_Of_Incidence = -Cos_Angle_Of_Incidence;
  444.     }
  445.   else
  446.     {
  447.     VScale (Local_Normal, *Layer_Normal, -1.0);
  448.     }
  449.  
  450.   VScale (Normal_Projection, Local_Normal, Cos_Angle_Of_Incidence);
  451.   VScale (Normal_Projection, Normal_Projection, 2.0);
  452.   VAdd (Reflect_Direction, *Eye, Normal_Projection);
  453.  
  454.   VDot (Cos_Angle_Of_Incidence, Reflect_Direction, Light_Source_Ray->Direction);
  455.   VLength (Normal_Length, Light_Source_Ray->Direction);
  456.  
  457.   if (Normal_Length == 0.0)
  458.     Cos_Angle_Of_Incidence = 0.0;
  459.   else 
  460.     Cos_Angle_Of_Incidence /= Normal_Length;
  461.  
  462.   if (Cos_Angle_Of_Incidence < 0.0)
  463.     Cos_Angle_Of_Incidence = 0;
  464.  
  465.   if (Finish->Phong_Size != 1.0)
  466.     Intensity = pow(Cos_Angle_Of_Incidence, Finish->Phong_Size);
  467.   else
  468.     Intensity = Cos_Angle_Of_Incidence;
  469.  
  470.   Intensity *= Finish->Phong;
  471.  
  472.   if (Finish->Metallic_Flag) 
  473.     {
  474.     Colour->Red+=Intensity*(Layer_Pigment_Colour->Red)*(Light_Colour->Red);    
  475.     Colour->Green+=Intensity*(Layer_Pigment_Colour->Green)*(Light_Colour->Green);
  476.     Colour->Blue+=Intensity*(Layer_Pigment_Colour->Blue)*(Light_Colour->Blue);  
  477.     }
  478.   else 
  479.     {
  480.     Colour->Red+=Intensity*(Light_Colour->Red);
  481.     Colour->Green+=Intensity*(Light_Colour->Green);
  482.     Colour->Blue+=Intensity*(Light_Colour->Blue);  
  483.     }
  484.   }
  485.  
  486. static void do_specular(Finish, Light_Source_Ray, REye, Layer_Normal, Colour, Light_Colour, Layer_Pigment_Colour)
  487. FINISH *Finish;
  488. RAY *Light_Source_Ray;
  489. VECTOR *Layer_Normal, *REye;
  490. COLOUR *Colour, *Light_Colour, *Layer_Pigment_Colour;
  491.   {
  492.   DBL Cos_Angle_Of_Incidence, Normal_Length, Intensity, Halfway_Length;
  493.   VECTOR Halfway;
  494.  
  495.   VHalf (Halfway, *REye, Light_Source_Ray->Direction);
  496.   VLength (Normal_Length, *Layer_Normal);
  497.   VLength (Halfway_Length, Halfway);
  498.   VDot (Cos_Angle_Of_Incidence, Halfway, *Layer_Normal);
  499.  
  500.   if (Normal_Length == 0.0 || Halfway_Length == 0.0)
  501.     Cos_Angle_Of_Incidence = 0.0;
  502.   else
  503.     Cos_Angle_Of_Incidence /= (Normal_Length * Halfway_Length);
  504.  
  505.   if (Cos_Angle_Of_Incidence < 0.0)
  506.     Cos_Angle_Of_Incidence = 0.0;
  507.  
  508.  
  509.   if (Finish->Roughness != 1.0)
  510.     Intensity = pow(Cos_Angle_Of_Incidence, Finish->Roughness);
  511.   else
  512.     Intensity = Cos_Angle_Of_Incidence;
  513.  
  514.   Intensity *= Finish->Specular;
  515.   if (Finish->Metallic_Flag) 
  516.     {
  517.     Colour->Red+=Intensity*(Layer_Pigment_Colour->Red)*(Light_Colour->Red);    
  518.     Colour->Green+=Intensity*(Layer_Pigment_Colour->Green)*(Light_Colour->Green);
  519.     Colour->Blue+=Intensity*(Layer_Pigment_Colour->Blue)*(Light_Colour->Blue);  
  520.     }
  521.   else 
  522.     {
  523.     Colour->Red+=Intensity*(Light_Colour->Red);
  524.     Colour->Green+=Intensity*(Light_Colour->Green);
  525.     Colour->Blue+=Intensity*(Light_Colour->Blue);
  526.     }
  527.   }
  528.  
  529. static void do_diffuse(Finish, Light_Source_Ray, Layer_Normal, Colour, Light_Colour, Layer_Pigment_Colour, Attenuation)
  530. FINISH *Finish;
  531. RAY *Light_Source_Ray;
  532. VECTOR *Layer_Normal;
  533. COLOUR *Colour, *Light_Colour, *Layer_Pigment_Colour;
  534. DBL Attenuation;
  535.   {
  536.   DBL Cos_Angle_Of_Incidence, Intensity;
  537.  
  538.   VDot (Cos_Angle_Of_Incidence, *Layer_Normal, Light_Source_Ray->Direction);
  539.   if (Cos_Angle_Of_Incidence < 0.0)
  540.     Cos_Angle_Of_Incidence = -Cos_Angle_Of_Incidence;
  541.  
  542.   if (Finish->Brilliance != 1.0)
  543.     Intensity = pow(Cos_Angle_Of_Incidence, Finish->Brilliance);
  544.   else
  545.     Intensity = Cos_Angle_Of_Incidence;
  546.  
  547.   Intensity *= Finish->Diffuse * Attenuation;
  548.  
  549.   if (Finish->Crand > 0.0)
  550.     Intensity -= ((rand()&0x7FFF)/(DBL) 0x7FFF) * Finish->Crand;
  551.  
  552.   Colour->Red += Intensity * (Layer_Pigment_Colour->Red) * (Light_Colour->Red);
  553.   Colour->Green += Intensity * (Layer_Pigment_Colour->Green) * (Light_Colour->Green);
  554.   Colour->Blue += Intensity * (Layer_Pigment_Colour->Blue) * (Light_Colour->Blue);
  555.   return;
  556.   }
  557.  
  558. /* Given a 3d point and a pigment, accumulate colour from that layer */
  559. /* Formerly called "Colour_At" */
  560. void Add_Pigment (Colour, Pigment, IPoint)
  561. COLOUR *Colour;
  562. PIGMENT *Pigment;
  563. VECTOR *IPoint;
  564.   {
  565.   register DBL x, y, z;
  566.   VECTOR TPoint,PTurbulence;
  567.  
  568.   if (Pigment->Trans != NULL) 
  569.     MInvTransPoint (&TPoint, IPoint, Pigment->Trans);
  570.   else 
  571.     TPoint = *IPoint;
  572.  
  573.   x = TPoint.x;
  574.   y = TPoint.y;
  575.   z = TPoint.z;
  576.   if(Pigment->Type != WOOD_PIGMENT &&
  577.     Pigment->Type != MARBLE_PIGMENT &&
  578.     Pigment->Type != NO_PIGMENT &&
  579.     Pigment->Type != COLOUR_PIGMENT &&
  580.     /*      Pigment->Type != SPOTTED_PIGMENT && */ /*maybe?*/
  581.     Pigment->Flags & HAS_TURB)
  582.     {
  583.     DTurbulence (&PTurbulence, x, y, z,
  584.       Pigment->omega,Pigment->lambda,Pigment->Octaves);
  585.     x += PTurbulence.x * Pigment->Turbulence.x;
  586.     y += PTurbulence.y * Pigment->Turbulence.y;
  587.     z += PTurbulence.z * Pigment->Turbulence.z;
  588.     }
  589.  
  590.  
  591.   if (x > COORDINATE_LIMIT)
  592.     x = COORDINATE_LIMIT;
  593.   else
  594.     if (x < -COORDINATE_LIMIT)
  595.       x = -COORDINATE_LIMIT;
  596.  
  597.   if (y > COORDINATE_LIMIT)
  598.     y = COORDINATE_LIMIT;
  599.   else
  600.     if (y < -COORDINATE_LIMIT)
  601.       y = -COORDINATE_LIMIT;
  602.  
  603.   if (z > COORDINATE_LIMIT)
  604.     z = COORDINATE_LIMIT;
  605.   else
  606.     if (z < -COORDINATE_LIMIT)
  607.       z = -COORDINATE_LIMIT;
  608.  
  609.   switch (Pigment->Type) 
  610.   {
  611.   case NO_PIGMENT:
  612.     /* No colouring pigment has been specified - make it black. */
  613.     Make_Colour (Colour, 0.0, 0.0, 0.0);
  614.     Colour -> Filter  = 0.0;
  615.     break;
  616.  
  617.   case COLOUR_PIGMENT:
  618.     Colour -> Red += Pigment->Colour1->Red;
  619.     Colour -> Green += Pigment->Colour1->Green;
  620.     Colour -> Blue += Pigment->Colour1->Blue;
  621.     Colour -> Filter += Pigment->Colour1->Filter;
  622.     break;
  623.  
  624.   case BOZO_PIGMENT: 
  625.     bozo (x, y, z, Pigment, Colour);
  626.     break;
  627.  
  628.   case MARBLE_PIGMENT:
  629.     marble (x, y, z, Pigment, Colour);
  630.     break;
  631.  
  632.   case WOOD_PIGMENT:
  633.     wood (x, y, z, Pigment, Colour);
  634.     break;
  635.  
  636.   case CHECKER_PIGMENT:
  637.     checker (x, y, z, Pigment, Colour);
  638.     break;
  639.  
  640.   case SPOTTED_PIGMENT:
  641.     spotted (x, y, z, Pigment, Colour);
  642.     break;
  643.  
  644.   case AGATE_PIGMENT:
  645.     agate (x, y, z, Pigment, Colour);
  646.     break;
  647.  
  648.   case GRANITE_PIGMENT:
  649.     granite (x, y, z, Pigment, Colour);
  650.     break;
  651.  
  652.   case GRADIENT_PIGMENT:
  653.     gradient (x, y, z, Pigment, Colour);
  654.     break;
  655.  
  656.   case HEXAGON_PIGMENT:
  657.     hexagon (x, y, z, Pigment, Colour);
  658.     break;
  659.  
  660.   case RADIAL_PIGMENT:
  661.     radial (x, y, z, Pigment, Colour);
  662.     break;
  663.  
  664.   case MANDEL_PIGMENT:
  665.     mandel (x, y, z, Pigment, Colour);
  666.     break;
  667.  
  668.   case IMAGE_MAP_PIGMENT:
  669.     image_map (x, y, z, Pigment, Colour);
  670.     break;
  671.  
  672.   case ONION_PIGMENT:
  673.     onion (x, y, z, Pigment, Colour);
  674.     break;
  675.  
  676.   case LEOPARD_PIGMENT:
  677.     leopard (x, y, z, Pigment, Colour);
  678.     break;
  679.  
  680.   case PAINTED1_PIGMENT:
  681.     painted1 (x, y, z, Pigment, Colour);
  682.     break;
  683.  
  684.   case PAINTED2_PIGMENT:
  685.     painted2 (x, y, z, Pigment, Colour);
  686.     break;
  687.  
  688.   case PAINTED3_PIGMENT:
  689.     painted3 (x, y, z, Pigment, Colour);
  690.     break;
  691.   }
  692.   }
  693.  
  694.  
  695. void Perturb_Normal(Layer_Normal, Tnormal, IPoint)
  696. VECTOR *Layer_Normal, *IPoint;
  697. TNORMAL *Tnormal;
  698.   {
  699.   register DBL x, y, z;
  700.   VECTOR TPoint,NTurbulence;
  701.  
  702.   if (Tnormal->Trans != NULL) 
  703.     MInvTransPoint (&TPoint, IPoint, Tnormal->Trans);
  704.   else 
  705.     TPoint = *IPoint;
  706.  
  707.   x = TPoint.x;
  708.   y = TPoint.y;
  709.   z = TPoint.z;
  710.  
  711.   if(Tnormal->Flags & HAS_TURB)
  712.     {
  713.     DTurbulence (&NTurbulence, x, y, z,
  714.       Tnormal->omega,Tnormal->lambda,Tnormal->Octaves);
  715.     x += NTurbulence.x * Tnormal->Turbulence.x;
  716.     y += NTurbulence.y * Tnormal->Turbulence.y;
  717.     z += NTurbulence.z * Tnormal->Turbulence.z;
  718.     }
  719.  
  720.  
  721.   switch (Tnormal->Type) 
  722.   {
  723.  
  724.   case WAVES: 
  725.     waves (x, y, z, Tnormal, Layer_Normal);
  726.     break;
  727.  
  728.   case RIPPLES: 
  729.     ripples (x, y, z, Tnormal, Layer_Normal);
  730.     break;
  731.  
  732.   case WRINKLES: 
  733.     wrinkles (x, y, z, Tnormal, Layer_Normal);
  734.     break;
  735.  
  736.   case BUMPS: 
  737.     bumps (x, y, z, Tnormal, Layer_Normal);
  738.     break;
  739.  
  740.   case DENTS: 
  741.     dents (x, y, z, Tnormal, Layer_Normal);
  742.     break; 
  743.  
  744.   case BUMPY1: 
  745.     bumpy1 (x, y, z, Tnormal, Layer_Normal);
  746.     break;
  747.  
  748.   case BUMPY2: 
  749.     bumpy2 (x, y, z, Tnormal, Layer_Normal);
  750.     break;
  751.  
  752.   case BUMPY3: 
  753.     bumpy3 (x, y, z, Tnormal, Layer_Normal);
  754.     break;
  755.  
  756.   case BUMP_MAP: 
  757.     bump_map (x, y, z, Tnormal, Layer_Normal);
  758.     break;
  759.   }
  760.   return;
  761.   }
  762.  
  763. void Diffuse (Finish, IPoint, Eye, Layer_Normal, Layer_Pigment_Colour, Colour, Attenuation, Object)
  764. FINISH *Finish;
  765. VECTOR *IPoint, *Layer_Normal;
  766. COLOUR *Layer_Pigment_Colour;
  767. COLOUR *Colour;
  768. RAY    *Eye;
  769. DBL    Attenuation;
  770. OBJECT *Object;
  771.   {
  772.   DBL Light_Source_Depth, Cos_Shadow_Angle;
  773.   RAY Light_Source_Ray;
  774.   LIGHT_SOURCE *Light_Source;
  775.   VECTOR REye;
  776.   COLOUR Light_Colour;
  777.  
  778.   if ((Finish->Diffuse == 0.0) && (Finish->Specular == 0.0) && (Finish->Phong == 0.0))
  779.     return;
  780.  
  781.   if (Finish->Specular != 0.0)
  782.     {
  783.     REye.x = -Eye->Direction.x;
  784.     REye.y = -Eye->Direction.y;
  785.     REye.z = -Eye->Direction.z;
  786.     }
  787.  
  788.   for (Light_Source = Frame.Light_Sources ; 
  789.   Light_Source != NULL;
  790.   Light_Source = Light_Source->Next_Light_Source)
  791.     {
  792.     /* Get a colour and a ray */
  793.  
  794.     do_light(Light_Source,       &Light_Source_Depth, 
  795.       &Light_Source_Ray,  IPoint,
  796.       &Light_Colour);
  797.  
  798.     /* Don't calculate spotlights when outside of the light's cone */
  799.     if (fabs(Light_Colour.Red) < BLACK_LEVEL && 
  800.       fabs(Light_Colour.Green) < BLACK_LEVEL && 
  801.       fabs(Light_Colour.Blue) < BLACK_LEVEL)
  802.       continue;
  803.  
  804.     /* See if light on far side of surface from camera. */
  805.  
  806.     if (!(Object->Type & DOUBLE_ILLUMINATE))
  807.       {
  808.        VDot(Cos_Shadow_Angle,*Layer_Normal,Light_Source_Ray.Direction);
  809.        if (Cos_Shadow_Angle < 0.0)
  810.          continue;
  811.       }
  812.  
  813.     /* If light source was not blocked by any intervening object, then
  814.       calculate it's contribution to the object's overall illumination */
  815.  
  816.     Shadow_Test_Flag = TRUE;
  817.     if (Quality_Flags & Q_SHADOW)
  818.       {
  819.       if ((Light_Source->Area_Light) && (Quality_Flags & Q_AREA_LIGHT))
  820.         Block_Area_Light (Light_Source, Light_Source_Depth,
  821.           &Light_Source_Ray, IPoint,
  822.           &Light_Colour, 0, 0, 0, 0, 0);
  823.       else
  824.         Block_Point_Light (Light_Source, Light_Source_Depth,
  825.           &Light_Source_Ray, &Light_Colour);
  826.       }
  827.     Shadow_Test_Flag = FALSE;
  828.  
  829.     if (fabs(Light_Colour.Red)  > BLACK_LEVEL || 
  830.       fabs(Light_Colour.Green) > BLACK_LEVEL || 
  831.       fabs(Light_Colour.Blue) > BLACK_LEVEL) 
  832.       {
  833.       if (Finish->Phong > 0.0) 
  834.         do_phong(Finish,&Light_Source_Ray,&Eye->Direction,Layer_Normal,Colour,&Light_Colour, Layer_Pigment_Colour);
  835.  
  836.       if (Finish->Specular > 0.0) 
  837.         do_specular(Finish,&Light_Source_Ray,&REye,Layer_Normal,Colour,&Light_Colour, Layer_Pigment_Colour);
  838.  
  839.       if (Finish->Diffuse > 0.0) 
  840.         do_diffuse(Finish,&Light_Source_Ray,Layer_Normal,Colour,&Light_Colour,Layer_Pigment_Colour, Attenuation);
  841.       }
  842.     }
  843.   return;
  844.   }
  845.  
  846. void Reflect (Reflection, IPoint, Ray, Layer_Normal, Colour)
  847. DBL Reflection;
  848. VECTOR *IPoint;
  849. RAY *Ray;
  850. VECTOR *Layer_Normal;
  851. COLOUR *Colour;
  852.   {
  853.   RAY New_Ray;
  854.   COLOUR Temp_Colour;
  855.   VECTOR Local_Normal;
  856.   VECTOR Normal_Projection;
  857.   VECTOR Surface_Offset;
  858.   register DBL Normal_Component;
  859.  
  860.   if (Reflection != 0.0)
  861.     {
  862.     Reflected_Rays_Traced++;
  863.     VDot (Normal_Component, Ray -> Direction, *Layer_Normal);
  864.     if (Normal_Component < 0.0) 
  865.       {
  866.       Local_Normal = *Layer_Normal;
  867.       Normal_Component *= -1.0;
  868.       }
  869.     else
  870.       VScale (Local_Normal, *Layer_Normal, -1.0);
  871.  
  872.     VScale (Normal_Projection, Local_Normal, Normal_Component);
  873.     VScale (Normal_Projection, Normal_Projection, 2.0);
  874.     VAdd (New_Ray.Direction, Ray -> Direction, Normal_Projection);
  875.     New_Ray.Initial = *IPoint;
  876.  
  877.     /* ARE 08/25/91 */
  878.  
  879.     VScale(Surface_Offset, New_Ray.Direction, 2.0 * Small_Tolerance); 
  880.     VAdd(New_Ray.Initial, New_Ray.Initial, Surface_Offset);           
  881.  
  882.     Copy_Ray_Containers (&New_Ray, Ray);
  883.     Trace_Level++;
  884.     Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
  885.     New_Ray.Quadric_Constants_Cached = FALSE;
  886.     Trace (&New_Ray, &Temp_Colour);
  887.     Trace_Level--;
  888.  
  889.     Colour -> Red   += Temp_Colour.Red   * Reflection;
  890.     Colour -> Green += Temp_Colour.Green * Reflection;
  891.     Colour -> Blue  += Temp_Colour.Blue  * Reflection;
  892.  
  893.     }
  894.   }
  895.  
  896. void Refract (Texture, IPoint, Ray, Top_Normal, Colour)
  897. TEXTURE *Texture;
  898. VECTOR *IPoint;
  899. RAY *Ray;
  900. VECTOR *Top_Normal;
  901. COLOUR *Colour;
  902.   {
  903.   RAY New_Ray;
  904.   COLOUR Temp_Colour;
  905.   VECTOR Local_Normal;
  906.   VECTOR Ray_Direction;
  907.   register DBL Normal_Component, Temp_IOR;
  908.   DBL temp, ior;
  909.   /*   int inside; */
  910.  
  911.   if (Top_Normal == NULL) 
  912.     {
  913.     New_Ray.Initial = *IPoint;
  914.     New_Ray.Direction = Ray->Direction;
  915.  
  916.     Copy_Ray_Containers (&New_Ray, Ray);
  917.     Trace_Level++;
  918.     Transmitted_Rays_Traced++;
  919.     Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
  920.     New_Ray.Quadric_Constants_Cached = FALSE;
  921.     Trace (&New_Ray, &Temp_Colour);
  922.     Trace_Level--;
  923.     (Colour -> Red) += Temp_Colour.Red;
  924.     (Colour -> Green) += Temp_Colour.Green;
  925.     (Colour -> Blue) += Temp_Colour.Blue;
  926.     }
  927.   else 
  928.     {
  929.     Refracted_Rays_Traced++;
  930.     VDot (Normal_Component, Ray -> Direction, *Top_Normal);
  931.     if (Normal_Component <= 0.0)
  932.       {
  933.       Local_Normal.x = Top_Normal -> x;
  934.       Local_Normal.y = Top_Normal -> y;
  935.       Local_Normal.z = Top_Normal -> z;
  936.       Normal_Component *= -1.0;
  937.       /*     inside = FALSE;*/
  938.       }
  939.     else
  940.       {
  941.       VScale (Local_Normal, *Top_Normal, -1.0);
  942.       /*     inside = TRUE;*/
  943.       }
  944.  
  945.  
  946.     Copy_Ray_Containers (&New_Ray, Ray);
  947.  
  948.     if (Ray -> Containing_Index == -1)
  949.       {
  950.       /* The ray is entering from the atmosphere */
  951.       Ray_Enter (&New_Ray, Texture);
  952.       ior = (Frame.Atmosphere_IOR)/(Texture->Finish->Index_Of_Refraction);
  953.       }
  954. else
  955.   {
  956.   /* The ray is currently inside an object */
  957.   if (New_Ray.Containing_Textures [New_Ray.Containing_Index] == Texture) 
  958.     /*         if (inside) */
  959.     {
  960.     /* The ray is leaving the current object */
  961.     Ray_Exit (&New_Ray);
  962.     if (New_Ray.Containing_Index == -1)
  963.       /* The ray is leaving into the atmosphere */
  964.     Temp_IOR = Frame.Atmosphere_IOR;
  965.     else
  966.       /* The ray is leaving into another object */
  967.       Temp_IOR = New_Ray.Containing_IORs [New_Ray.Containing_Index];
  968.  
  969.     ior =  (Texture->Finish->Index_Of_Refraction)/Temp_IOR;
  970.     }
  971.     else
  972.       {
  973.       /* The ray is entering a new object */
  974.       Temp_IOR = New_Ray.Containing_IORs [New_Ray.Containing_Index];
  975.       Ray_Enter (&New_Ray, Texture);
  976.  
  977.       ior =  Temp_IOR / (Texture->Finish->Index_Of_Refraction);
  978.       }
  979.     }
  980.  
  981.   temp = 1.0 + ior * ior * (Normal_Component * Normal_Component - 1.0);
  982.   if (temp < 0.0) 
  983.       {
  984.     Reflect ((1.0 - Texture->Finish->Reflection), IPoint, 
  985.     Ray, Top_Normal, Colour);
  986.     return;
  987.     }
  988.  
  989.   temp = ior*Normal_Component - sqrt(temp);
  990.   VScale (Local_Normal, Local_Normal, temp);
  991.   VScale (Ray_Direction, Ray->Direction, ior);
  992.   VAdd (New_Ray.Direction, Local_Normal, Ray_Direction);
  993.   VNormalize (New_Ray.Direction, New_Ray.Direction);
  994.  
  995.   New_Ray.Initial = *IPoint;
  996.   Trace_Level++;
  997.   Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
  998.   New_Ray.Quadric_Constants_Cached = FALSE;
  999.  
  1000.   Trace (&New_Ray, &Temp_Colour);
  1001.   Trace_Level--;
  1002.  
  1003.   (Colour -> Red) += (Temp_Colour.Red)
  1004.     * (Texture -> Finish->Refraction);
  1005.   (Colour -> Green) += (Temp_Colour.Green)
  1006.     * (Texture -> Finish->Refraction);
  1007.   (Colour -> Blue) += (Temp_Colour.Blue)
  1008.     * (Texture -> Finish->Refraction);
  1009.   }
  1010. }
  1011.  
  1012. void Fog (Distance, Fog_Colour, Fog_Distance, Colour)
  1013. DBL Distance, Fog_Distance;
  1014. COLOUR *Fog_Colour, *Colour;
  1015.   {
  1016.   DBL Fog_Factor, Fog_Factor_Inverse;
  1017.  
  1018.   Fog_Factor = exp(-1.0 * Distance/Fog_Distance);
  1019.   Fog_Factor_Inverse = 1.0 - Fog_Factor;
  1020.   Colour->Red = Colour->Red*Fog_Factor + Fog_Colour->Red*Fog_Factor_Inverse;
  1021.   Colour->Green = Colour->Green*Fog_Factor + Fog_Colour->Green*Fog_Factor_Inverse;
  1022.   Colour->Blue = Colour->Blue*Fog_Factor + Fog_Colour->Blue*Fog_Factor_Inverse;
  1023.   }
  1024.  
  1025. void Compute_Reflected_Colour (Ray, Finish, Ray_Intersection, Layer_Pigment_Colour, Filter_Colour, Colour, Layer_Normal)
  1026. RAY *Ray;
  1027. FINISH *Finish;
  1028. INTERSECTION *Ray_Intersection;
  1029. COLOUR *Layer_Pigment_Colour;
  1030. COLOUR *Filter_Colour;
  1031. COLOUR *Colour;
  1032. VECTOR *Layer_Normal;
  1033.   {
  1034.   DBL Attenuation, Ambient;
  1035.   COLOUR Emitted_Colour;
  1036.  
  1037.   /* This variable keeps track of how much colour comes from the surface
  1038.       of the object and how much is transmited through. */
  1039.   Make_Colour (&Emitted_Colour, 0.0, 0.0, 0.0);
  1040.  
  1041.   if (Quality_Flags & Q_FULL_AMBIENT) 
  1042.     {
  1043.     Layer_Pigment_Colour->Filter = 0.0;
  1044.  
  1045.     Colour->Red   += Layer_Pigment_Colour->Red * Filter_Colour->Filter;
  1046.     Colour->Green += Layer_Pigment_Colour->Green * Filter_Colour->Filter;
  1047.     Colour->Blue  += Layer_Pigment_Colour->Blue * Filter_Colour->Filter;
  1048.     return;
  1049.     }
  1050.  
  1051.   Attenuation = Filter_Colour->Filter * (1.0 - Layer_Pigment_Colour->Filter);
  1052.  
  1053.   if ((Ambient = Finish->Ambient*Attenuation) != 0.0)
  1054.     {
  1055.     Emitted_Colour.Red += Layer_Pigment_Colour->Red * Ambient;
  1056.     Emitted_Colour.Green += Layer_Pigment_Colour->Green * Ambient;
  1057.     Emitted_Colour.Blue += Layer_Pigment_Colour->Blue * Ambient;
  1058.     }
  1059.  
  1060.   Diffuse (Finish, &Ray_Intersection->IPoint, Ray,
  1061.     Layer_Normal, Layer_Pigment_Colour, &Emitted_Colour, Attenuation, 
  1062.     Ray_Intersection->Object);
  1063.  
  1064.   Colour->Red   += Emitted_Colour.Red;
  1065.   Colour->Green += Emitted_Colour.Green;
  1066.   Colour->Blue  += Emitted_Colour.Blue;
  1067.  
  1068.   if (Quality_Flags & Q_REFLECT)
  1069.     Reflect (Finish->Reflection, &Ray_Intersection -> IPoint, Ray,
  1070.       Layer_Normal, Colour); 
  1071.   }
  1072.  
  1073. /* Given an intersection point, a ray, & a shadow flag, add that point's
  1074.   color to the given colour and return it. */
  1075.  
  1076. void Determine_Apparent_Colour (Ray_Intersection, Colour, Ray)
  1077. INTERSECTION *Ray_Intersection;
  1078. COLOUR *Colour;
  1079. RAY *Ray;
  1080.   {
  1081.   COLOUR Layer_Pigment_Colour, Refracted_Colour, Filter_Colour;
  1082.   TEXTURE *Layer, *Texture;
  1083.   FINISH *Finish;
  1084.   VECTOR Layer_Normal, Raw_Normal, Top_Normal;
  1085.   DBL Normal_Direction;
  1086.   int layer_number;
  1087.  
  1088. #define QColour Texture->Pigment->Quick_Colour
  1089.  
  1090.   /* Get the normal to the surface */
  1091.   if (Ray_Intersection->NFlag)
  1092.      Raw_Normal = Ray_Intersection->INormal;
  1093.   else
  1094.      Normal (&Raw_Normal, Ray_Intersection->Object, &Ray_Intersection->IPoint);
  1095.  
  1096.   /* Now, we perform the lighting calculations. */
  1097.  
  1098.   /* We assume here that Post_Process has propagated all parent
  1099.    textures to the object itself and that everything has some texture.
  1100.    Redirrect to the proper texture if its a material or checker texture */
  1101.  
  1102.   for (Texture = Ray_Intersection->Object->Texture;
  1103.   Texture->Type != PNF_TEXTURE;)
  1104.     switch (Texture->Type)
  1105.     {
  1106.     case TILE_TEXTURE:
  1107.       Texture = tiles_texture(&Ray_Intersection->IPoint,((TILES *)Texture));
  1108.       break;
  1109.     case MAT_TEXTURE:
  1110.       Texture = material_map(&Ray_Intersection->IPoint,((MATERIAL *)Texture));
  1111.       break;
  1112.     default:
  1113.       fprintf(stderr, "Bad texture type: %d\n", Texture->Type);
  1114.       close_all(); 
  1115.       exit(1);
  1116.     };
  1117.  
  1118.   Make_ColourA (&Filter_Colour, 1.0, 1.0, 1.0, 1.0);
  1119.   for (layer_number=1 , Layer = Texture;
  1120.   (Layer != NULL) && (fabs(Filter_Colour.Filter) > BLACK_LEVEL);
  1121.   layer_number++, Layer = Layer->Next_Layer)
  1122.     {
  1123.     Make_Colour (&Layer_Pigment_Colour, 0.0, 0.0, 0.0);
  1124.     if (Quality_Flags & Q_QUICKC)
  1125.       Layer_Pigment_Colour = QColour;
  1126.     else
  1127.       Add_Pigment (&Layer_Pigment_Colour, Layer->Pigment, &Ray_Intersection->IPoint);
  1128.  
  1129.     Layer_Normal = Raw_Normal;
  1130.     if ((Quality_Flags & Q_NORMAL) && (Texture->Tnormal != NULL))
  1131.       Perturb_Normal (&Layer_Normal, Texture->Tnormal,
  1132.         &Ray_Intersection->IPoint);
  1133.  
  1134.     /* If the surface normal points away, flip its direction. */
  1135.     VDot (Normal_Direction, Layer_Normal, Ray->Direction);
  1136.     if (Normal_Direction > 0.0) 
  1137.       {
  1138.       VScaleEq (Layer_Normal, -1.0);
  1139.       }
  1140.     if (layer_number == 1)
  1141.       Top_Normal = Layer_Normal;
  1142.  
  1143.     Compute_Reflected_Colour (Ray,
  1144.       Layer->Finish,
  1145.       Ray_Intersection,
  1146.       &Layer_Pigment_Colour,
  1147.       &Filter_Colour,
  1148.       Colour, &Layer_Normal);
  1149.  
  1150.     Filter_Colour.Red   *= Layer_Pigment_Colour.Red;
  1151.     Filter_Colour.Green *= Layer_Pigment_Colour.Green;
  1152.     Filter_Colour.Blue  *= Layer_Pigment_Colour.Blue;
  1153.     Filter_Colour.Filter *= Layer_Pigment_Colour.Filter;
  1154.     }
  1155.  
  1156.   Finish = Texture->Finish;
  1157.  
  1158.   if ((fabs(Filter_Colour.Filter) > BLACK_LEVEL) && (Quality_Flags & Q_REFRACT))
  1159.     {
  1160.     Make_Colour (&Refracted_Colour, 0.0, 0.0, 0.0);
  1161.  
  1162.     if (Finish->Refraction > 0.0)
  1163.       Refract (Texture, &Ray_Intersection -> IPoint, Ray,
  1164.         &Top_Normal, &Refracted_Colour);
  1165.     else
  1166.       Refract (Texture, &Ray_Intersection->IPoint, Ray,
  1167.         NULL, &Refracted_Colour);
  1168.  
  1169.     Colour->Red += Filter_Colour.Red * Refracted_Colour.Red * Filter_Colour.Filter;
  1170.     Colour->Green += Filter_Colour.Green * Refracted_Colour.Green * Filter_Colour.Filter;
  1171.     Colour->Blue += Filter_Colour.Blue * Refracted_Colour.Blue * Filter_Colour.Filter;
  1172.     }
  1173.  
  1174.   if (Frame.Fog_Distance != 0.0)
  1175.     Fog (Ray_Intersection->Depth, &Frame.Fog_Colour, Frame.Fog_Distance,
  1176.       Colour);
  1177.   }
  1178.  
  1179. void Filter_Shadow_Ray (Ray_Intersection, Colour)
  1180. INTERSECTION *Ray_Intersection;
  1181. COLOUR *Colour;
  1182.   {
  1183.   COLOUR Layer_Pigment_Colour, Filter_Colour;
  1184.   TEXTURE *Layer, *Texture;
  1185.   FINISH *Finish;
  1186.   int layer_number;
  1187.  
  1188. #define QColour Texture->Pigment->Quick_Colour
  1189.  
  1190.   if (!(Quality_Flags & Q_SHADOW))
  1191.     return;
  1192.  
  1193.   /* Now, we perform the lighting calculations. */
  1194.  
  1195.   /* We assume here that Post_Process has propagated all parent
  1196.    textures to the object itself and that everything has some texture.
  1197.    Redirrect to the proper texture if its a material or checker texture */
  1198.  
  1199.   for (Texture = Ray_Intersection->Object->Texture;
  1200.   Texture->Type != PNF_TEXTURE;)
  1201.     switch (Texture->Type)
  1202.     {
  1203.     case TILE_TEXTURE:
  1204.       Texture = tiles_texture(&Ray_Intersection->IPoint,((TILES *)Texture));
  1205.       break;
  1206.     case MAT_TEXTURE:
  1207.       Texture = material_map(&Ray_Intersection->IPoint,((MATERIAL *)Texture));
  1208.       break;
  1209.     default:
  1210.       fprintf(stderr, "Bad texture type: %d\n", Texture->Type);
  1211.       close_all(); 
  1212.       exit(1);
  1213.     };
  1214.  
  1215.   Make_ColourA (&Filter_Colour, 1.0, 1.0, 1.0, 1.0);
  1216.   for (layer_number=1 , Layer = Texture;
  1217.   (Layer != NULL) && (fabs(Filter_Colour.Filter) > BLACK_LEVEL);
  1218.   layer_number++, Layer = Layer->Next_Layer)
  1219.     {
  1220.     if (Quality_Flags & Q_QUICKC)
  1221.       Layer_Pigment_Colour = QColour;
  1222.     else
  1223.       {
  1224.       Make_Colour (&Layer_Pigment_Colour, 0.0, 0.0, 0.0);
  1225.       Add_Pigment (&Layer_Pigment_Colour, Layer->Pigment, &Ray_Intersection->IPoint);
  1226.       }
  1227.  
  1228.     Filter_Colour.Red   *= Layer_Pigment_Colour.Red;
  1229.     Filter_Colour.Green *= Layer_Pigment_Colour.Green;
  1230.     Filter_Colour.Blue  *= Layer_Pigment_Colour.Blue;
  1231.     Filter_Colour.Filter *= Layer_Pigment_Colour.Filter;
  1232.     }
  1233.  
  1234.   Finish = Texture->Finish;
  1235.  
  1236.   /* For shadow rays, we have the filter colour now - time to return */
  1237.   if (fabs(Filter_Colour.Filter) < BLACK_LEVEL) 
  1238.     {
  1239.     Make_Colour (Colour, 0.0, 0.0, 0.0);
  1240.     return;
  1241.     }
  1242.  
  1243.   if (Finish->Refraction > 0.0) 
  1244.     {
  1245.     Colour->Red *= Filter_Colour.Red * Finish->Refraction * Filter_Colour.Filter;
  1246.     Colour->Green *= Filter_Colour.Green * Finish->Refraction * Filter_Colour.Filter;
  1247.     Colour->Blue *= Filter_Colour.Blue * Finish->Refraction * Filter_Colour.Filter;
  1248.     }
  1249.   else 
  1250.     {
  1251.     Colour->Red *= Filter_Colour.Red * Filter_Colour.Filter;
  1252.     Colour->Green *= Filter_Colour.Green * Filter_Colour.Filter;
  1253.     Colour->Blue *= Filter_Colour.Blue * Filter_Colour.Filter;
  1254.     }
  1255.   return;
  1256.  
  1257.   }
  1258.